

#ifndef PF_MODIFICATION_H
#define PF_MODIFICATION_H

#include "pf_vector.h"
#include "pf_pen.h"
#include "lx_Export.h"

class PF_AtomicEntity;
class PF_Entity;
class PF_Container;
class PF_Text;
class PF_Polyline;
class PF_Document;
class PF_Graphic;
class PF_GraphicView;

/**
 * Holds the data needed for move modifications.
 */
class LX_EXPORT PF_MoveAttribute {
public:
    int number;
    bool useCurrentAttributes;
    bool useCurrentLayer;
    PF_Vector offset;
};



/**
 * Holds the data needed for rotation modifications.
 */
class LX_EXPORT PF_RotateAttribute {
public:
    int number;
    bool useCurrentAttributes;
    bool useCurrentLayer;
    PF_Vector center;
    double angle;
};



/**
 * Holds the data needed for scale modifications.
 */
class LX_EXPORT PF_ScaleAttribute {
public:
    int number;
    bool useCurrentAttributes;
    bool useCurrentLayer;
    PF_Vector referencePoint;
    double factor;
};


/**
 * Holds the data needed for mirror modifications.
 */
class LX_EXPORT PF_MirrorAttribute {
public:
    bool copy;
    bool useCurrentAttributes;
    bool useCurrentLayer;
    PF_Vector axisPoint1;
    PF_Vector axisPoint2;
};


/**
 * Holds the data needed for move/rotate modifications.
 */
class LX_EXPORT PF_MoveRotateAttribute {
public:
    int number;
    bool useCurrentAttributes;
    bool useCurrentLayer;
    PF_Vector referencePoint;
	PF_Vector offset;
	double angle;
};



/**
 * Holds the data needed for rotation around two centers modifications.
 */
class LX_EXPORT PF_Rotate2Attribute {
public:
    int number;
    bool useCurrentAttributes;
    bool useCurrentLayer;
    PF_Vector center1;
    PF_Vector center2;
    double angle1;
    double angle2;
};



/**
 * Holds the data needed for beveling modifications.
 */
class LX_EXPORT PF_BevelAttribute {
public:
	double length1;
	double length2;
	bool trim;
};




/**
 * Holds the data needed for rounding modifications.
 */
class LX_EXPORT PF_RoundAttribute {
public:
	double radius;
	bool trim;
};


/**
 * Holds the data needed for moving reference points.
 */
class LX_EXPORT PF_MoveRefAttribute {
public:
	PF_Vector ref;
    PF_Vector offset;
};



/**
 * Holds the data needed for changing attributes.
 */
class LX_EXPORT PF_AttributesData {
public:
        QString layer;
	PF_Pen pen;
	bool changeLayer;
	bool changeColor;
	bool changeLineType;
	bool changeWidth;
};


/**
 * Holds the data needed for pasting.
 */
class LX_EXPORT PF_PasteAttribute {
public:
	PF_PasteAttribute(PF_Vector insertionPoint,
		double factor,
		double angle,
		bool asInsert,
                const QString& blockName) {

		this->insertionPoint = insertionPoint;
		this->factor = factor;
		this->angle = angle;
		this->asInsert = asInsert;
		this->blockName = blockName;
	}
	
	//! Insertion point.
	PF_Vector insertionPoint;
	//! Scale factor.
	double factor;
	//! Rotation angle.
	double angle;
	//! Paste as an insert rather than individual entities.
	bool asInsert;
	//! Name of the block to create or an empty string to assign a new auto name.
        QString blockName;
};


/**
 * API Class for manipulating entities. 
 * There's no interaction handled in this class.
 * 
 * All modifications can be undone / redone if the container 
 * is a PF_Graphic.
 *
 * This class is connected to an entity container and
 * can be connected to a graphic view.
 *

 */
class LX_EXPORT PF_Modification {
public:
    PF_Modification(PF_Container& entityContainer,
                    PF_GraphicView* graphicView=NULL,
					bool handleUndo=true);

	void remove();
    bool changeAttributes(PF_AttributesData& data);

	void copy(const PF_Vector& ref, const bool cut);
private:
	void copyEntity(PF_Entity* e, const PF_Vector& ref, const bool cut);
public:
	void copyLayers(PF_Entity* e);
	void copyBlocks(PF_Entity* e);
	void paste(const PF_PasteAttribute& data, PF_Graphic* source=NULL);

    bool move(PF_MoveAttribute& data);
    bool rotate(PF_RotateAttribute& data);
    bool scale(PF_ScaleAttribute& data);
    bool mirror(PF_MirrorAttribute& data);
    bool moveRotate(PF_MoveRotateAttribute& data);
    bool rotate2(PF_Rotate2Attribute& data);
	
    bool trim(const PF_Vector& trimCoord, PF_AtomicEntity* trimEntity,
              const PF_Vector& limitCoord, PF_Entity* limitEntity,
			  bool both);
    bool trimAmount(const PF_Vector& trimCoord, PF_AtomicEntity* trimEntity,
	          double dist);

    bool cut(const PF_Vector& cutCoord, PF_AtomicEntity* cutEntity);
    bool stretch(const PF_Vector& firstCorner,
				const PF_Vector& secondCorner,
				const PF_Vector& offset);
				
    bool bevel(const PF_Vector& coord1, PF_AtomicEntity* entity1,
              const PF_Vector& coord2, PF_AtomicEntity* entity2,
			  PF_BevelAttribute& data);
    bool round(const PF_Vector& coord, 
               const PF_Vector& coord1,
	           PF_AtomicEntity* entity1,
               const PF_Vector& coord2,
               PF_AtomicEntity* entity2,
			   PF_RoundAttribute& data);

	bool explode();
	bool explodeTextIntoLetters();
        bool explodeTextIntoLetters(PF_Text* text, QList<PF_Entity*>& addList);
    bool moveRef(PF_MoveRefAttribute& data);

    bool splitPolyline(PF_Polyline& polyline,
                       PF_Entity& e1, PF_Vector v1,
                       PF_Entity& e2, PF_Vector v2,
                       PF_Polyline** polyline1,
                       PF_Polyline** polyline2) const;
	PF_Polyline* addPolylineNode(PF_Polyline& polyline,
	             const PF_AtomicEntity& segment,
				 const PF_Vector& node);
	PF_Polyline* deletePolylineNode(PF_Polyline& polyline, 
				const PF_Vector& node);
	PF_Polyline* deletePolylineNodesBetween(PF_Polyline& polyline, PF_AtomicEntity& segment,
				const PF_Vector& node1, const PF_Vector& node2);
	PF_Polyline* polylineTrim(PF_Polyline& polyline, 
				PF_AtomicEntity& segment1, 
				PF_AtomicEntity& segment2);

private:
    void deselectOriginals(bool remove);
    void addNewEntities(QList<PF_Entity*>& addList);

protected:
    PF_Container* container;
    PF_Graphic* graphic;
    PF_Document* document;
    PF_GraphicView* graphicView;
	bool handleUndo;
};

#endif
